package org.hospital.entity;

// default package

import java.sql.Date;
import java.sql.Timestamp;
import java.util.List;

import org.hibernate.Criteria;
import org.hibernate.LockOptions;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Restrictions;

import static org.hibernate.criterion.Example.create;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

/**
 * A data access object (DAO) providing persistence and search support for Bill
 * entities. Transaction control of the save(), update() and delete() operations
 * can directly support Spring container-managed transactions or they can be
 * augmented to handle user-managed Spring transactions. Each of these methods
 * provides additional information for how to configure it for the desired type
 * of transaction control.
 * 
 * @see .Bill
 * @author MyEclipse Persistence Tools
 */
@Transactional(propagation = Propagation.REQUIRED,rollbackFor=Exception.class)
public class BillDAO {
	private static final Logger log = LoggerFactory.getLogger(BillDAO.class);
	// property constants
	public static final String CLIENT_ID = "clientId";
	public static final String OPERATOR_ID = "operatorId";
	public static final String DOCTOR_ID = "doctorId";
	public static final String DEPARTMENT_ID = "departmentId";
	public static final String CLINIC_ID = "clinicId";
	public static final String CATEGORY = "category";
	public static final String TOTAL_COST = "totalCost";
	public static final String TOTAL_PRICE = "totalPrice";
	public static final String STATUS = "status";

	private SessionFactory sessionFactory;

	public void setSessionFactory(SessionFactory sessionFactory) {
		this.sessionFactory = sessionFactory;
	}

	private Session getCurrentSession() {
		return sessionFactory.getCurrentSession();
	}

	protected void initDao() {
		// do nothing
	}
	
	public Bill getClinicFirstBill(int clinicId) {
		log.debug("getClinicFirstBill");
		try {
			Criteria c = getCurrentSession().createCriteria(Bill.class);
			c.add(Restrictions.eq("clinicId", clinicId));
			c.addOrder(Order.asc("datetime"));
			c.setMaxResults(1);
			return (Bill)c.uniqueResult();
		} catch (RuntimeException re) {
			log.error("getClinicFirstBill failed", re);
			throw re;
		}
	}
	
	/**
	 * 获取[startTime,endTime]门诊指定费油项目开单细节
	 * @param clinic
	 * @param fundProjectId
	 * @param startTime
	 * @param endTime
	 * @return
	 */
	public List<BillProject> getFundBPSummary(int clinicId,int fundProjectId,long startTime,long endTime){
		log.debug("getFundBPSummary");
		try {
			StringBuilder hql = new StringBuilder();
        	hql.append("SELECT bp ");
        	hql.append("FROM Bill as b,BillProject as bp ");
        	hql.append("WHERE b.billId = bp.id.billId ");
        	hql.append("AND b.status = 0 ");
        	hql.append("AND b.category = 'fundBill' ");
        	hql.append("AND bp.id.projectId = :projectId ");
        	hql.append("AND b.clinicId >= :clinicId ");
        	hql.append("AND b.datetime >= :startTime ");
        	hql.append("AND b.datetime < :endTime ");
        	
			Query q = getCurrentSession().createQuery(hql.toString());
			q.setParameter("projectId", fundProjectId);
			q.setParameter("clinicId", clinicId);
			q.setParameter("startTime", new Date(startTime));
			q.setParameter("endTime", new Date(endTime));
			List<BillProject> result = q.list();
			log.debug("getFundBPSummary successful");
			return result;
		} catch (RuntimeException re) {
			log.error("getFundBPSummary failed", re);
			throw re;
		}
	}
	
	/**
	 * 获取治疗项目[startTime,endTime]中特定治疗项目开单细节
	 * @param id  status=0:科室Id;status=1:门诊Id;
	 * @param treatProjectId
	 * @param startTime
	 * @param endTime
	 * @param status 0：查询部门内的；1：查询门诊内的
	 * @return 
	 */
	public List<BillProject> getBillProjectSummary(int id, int treatProjectId, long startTime,
			long endTime,int status) {
		log.debug("getClinicTreatmentProjectSummary");
		try {
			String hql="";
			if(status == 1) {
				hql = "SELECT bp "
					+ "FROM Bill AS b,BillProject AS bp "
					+ "WHERE b.billId = bp.id.billId "
					+ "AND b.status = 0 "
					+ "AND b.category = 'treatmentBill' "
					+ "AND b.datetime >= :startTime "
					+ "AND b.datetime < :endTime "
					+ "AND bp.id.projectId = :projectId "
					+ "AND b.clinicId = :id";
			}
			if(status == 0) {
				hql = "SELECT bp "
					+ "FROM Bill AS b,BillProject AS bp "
					+ "WHERE b.billId = bp.id.billId "
					+ "AND b.status = 0 "
					+ "AND b.category = 'treatmentBill' "
					+ "AND b.datetime >= :startTime "
					+ "AND b.datetime < :endTime "
					+ "AND bp.id.projectId = :projectId "
					+ "AND b.departmentId = :id";
			}
			
			Query q = getCurrentSession().createQuery(hql);
			q.setParameter("startTime", new Date(startTime));
			q.setParameter("endTime", new Date(endTime));
			q.setParameter("projectId", treatProjectId);
			q.setParameter("id", id);
			List<BillProject> result = q.list();
			log.debug("getClinicTreatmentProjectSummary successful");
			return result;
		} catch (RuntimeException re) {
			log.error("getClinicTreatmentProjectSummary failed", re);
			throw re;
		}
	}
	
	/**
	 * 获取医生在[startTime,endTime]开的单
	 * @param id status=0:科室Id;status=1:门诊Id;
	 * @param doctor
	 * @param treatProjectId
	 * @param startTime
	 * @param endTime
	 * @param status  0：查询部门内的；1：查询门诊内的
	 * @return
	 */
	public List<BillProject> getDoctorSummaryInProject(int id,Employee doctor,int treatProjectId,long startTime,long endTime,int status) {
		log.debug("getDoctorSummaryInProject");
		try {
			String hql="";
			if(status == 1) {
				hql = "SELECT bp "
					+ "FROM Bill AS b,BillProject AS bp "
					+ "WHERE b.billId = bp.id.billId "
					+ "AND b.status = 0 "
					+ "AND b.category = 'treatmentBill' "
					+ "AND bp.id.projectId = :projectId "
					+ "AND b.clinicId = :id "
					+ "AND b.doctorId = :doctorId "
					+ "AND b.datetime >= :startTime "
					+ "AND b.datetime < :endTime ";
			}
			if(status == 0) {
				hql = "SELECT bp "
					+ "FROM Bill AS b,BillProject AS bp "
					+ "WHERE b.billId = bp.id.billId "
					+ "AND b.status = 0 "
					+ "AND b.category = 'treatmentBill' "
					+ "AND bp.id.projectId = :projectId "
					+ "AND b.departmentId = :id "
					+ "AND b.doctorId = :doctorId "
					+ "AND b.datetime >= :startTime "
					+ "AND b.datetime < :endTime ";
			}
			
			Query q = getCurrentSession().createQuery(hql);
			q.setParameter("id", id);
			q.setParameter("projectId", treatProjectId);
			q.setParameter("doctorId", doctor.getEmployeeId());
			q.setParameter("startTime", new Date(startTime));
			q.setParameter("endTime", new Date(endTime));

			List<BillProject> result = q.list();
			log.debug("getDoctorSummaryInProject successful");
			return result;
		} catch (RuntimeException re) {
			log.error("getDoctorSummaryInProject failed", re);
			throw re;
		}
	}
	/**
	 * 获取单据表数据
	 * @param date1
	 * @param date2
	 * @param category
	 */
	public List<Bill> getBillData(Timestamp date1,Timestamp date2,String category){
		StringBuilder hql = new StringBuilder();
		try{
			hql.append("SELECT b ");
			hql.append("FROM Bill AS b ");
			hql.append("WHERE ");
			hql.append("b.category = :category ");
			hql.append("AND b.datetime >= :date1 ");
			hql.append("AND b.datetime <= :date2");
			
			Query q = getCurrentSession().createQuery(hql.toString());
			q.setParameter("category", category);
			q.setParameter("date1", date1);
			q.setParameter("date2", date2);
			List<Bill> result = q.list();
			return result;
		}catch(RuntimeException re) {
			log.error("getDoctorSummaryInProject failed", re);
			throw re;
		}
	}
	
	public void save(Bill transientInstance) {
		log.debug("saving Bill instance");
		try {
			getCurrentSession().save(transientInstance);
			log.debug("save successful");
		} catch (RuntimeException re) {
			log.error("save failed", re);
			throw re;
		}
	}

	public void delete(Bill persistentInstance) {
		log.debug("deleting Bill instance");
		try {
			getCurrentSession().delete(persistentInstance);
			log.debug("delete successful");
		} catch (RuntimeException re) {
			log.error("delete failed", re);
			throw re;
		}
	}

	public Bill findById(java.lang.Integer id) {
		log.debug("getting Bill instance with id: " + id);
		try {
			Bill instance = (Bill) getCurrentSession().get("org.hospital.entity.Bill", id);
			return instance;
		} catch (RuntimeException re) {
			log.error("get failed", re);
			throw re;
		}
	}

	public List<Bill> findByExample(Bill instance) {
		log.debug("finding Bill instance by example");
		try {
			List<Bill> results = (List<Bill>) getCurrentSession().createCriteria("Bill")
					.add(create(instance)).list();
			log.debug("find by example successful, result size: " + results.size());
			return results;
		} catch (RuntimeException re) {
			log.error("find by example failed", re);
			throw re;
		}
	}

	public List findByProperty(String propertyName, Object value) {
		log.debug("finding Bill instance with property: " + propertyName + ", value: " + value);
		try {
			String queryString = "from Bill as model where model." + propertyName + "= ?";
			Query queryObject = getCurrentSession().createQuery(queryString);
			queryObject.setParameter(0, value);
			return queryObject.list();
		} catch (RuntimeException re) {
			log.error("find by property name failed", re);
			throw re;
		}
	}

	public List<Bill> findByClientId(Object clientId) {
		return findByProperty(CLIENT_ID, clientId);
	}

	public List<Bill> findByOperatorId(Object operatorId) {
		return findByProperty(OPERATOR_ID, operatorId);
	}

	public List<Bill> findByDoctorId(Object doctorId) {
		return findByProperty(DOCTOR_ID, doctorId);
	}

	public List<Bill> findByDepartmentId(Object departmentId) {
		return findByProperty(DEPARTMENT_ID, departmentId);
	}

	public List<Bill> findByClinicId(Object clinicId) {
		return findByProperty(CLINIC_ID, clinicId);
	}

	public List<Bill> findByCategory(Object category) {
		return findByProperty(CATEGORY, category);
	}

	public List<Bill> findByTotalCost(Object totalCost) {
		return findByProperty(TOTAL_COST, totalCost);
	}

	public List<Bill> findByTotalPrice(Object totalPrice) {
		return findByProperty(TOTAL_PRICE, totalPrice);
	}

	public List<Bill> findByStatus(Object status) {
		return findByProperty(STATUS, status);
	}

	public List findAll() {
		log.debug("finding all Bill instances");
		try {
			String queryString = "from Bill";
			Query queryObject = getCurrentSession().createQuery(queryString);
			return queryObject.list();
		} catch (RuntimeException re) {
			log.error("find all failed", re);
			throw re;
		}
	}

	public Bill merge(Bill detachedInstance) {
		log.debug("merging Bill instance");
		try {
			Bill result = (Bill) getCurrentSession().merge(detachedInstance);
			log.debug("merge successful");
			return result;
		} catch (RuntimeException re) {
			log.error("merge failed", re);
			throw re;
		}
	}

	public void attachDirty(Bill instance) {
		log.debug("attaching dirty Bill instance");
		try {
			getCurrentSession().saveOrUpdate(instance);
			log.debug("attach successful");
		} catch (RuntimeException re) {
			log.error("attach failed", re);
			throw re;
		}
	}

	public void attachClean(Bill instance) {
		log.debug("attaching clean Bill instance");
		try {
			getCurrentSession().buildLockRequest(LockOptions.NONE).lock(instance);
			log.debug("attach successful");
		} catch (RuntimeException re) {
			log.error("attach failed", re);
			throw re;
		}
	}

	public static BillDAO getFromApplicationContext(ApplicationContext ctx) {
		return (BillDAO) ctx.getBean("BillDAO");
	}
}